/*
 * SpeedoDyno - Speedometer and dynamometer application for Android 
 * Copyright 2013 Guilhem VALENTIN
 * 
 * This file is part of SpeedoDyno
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SpeedoDyno. If not, see <http://www.gnu.org/licenses/>.
 */
package com.gvalentin.speedodyno.data;

import android.location.Location;

/**
 * Calculates acceleration
 * @author guilhem
 */
public class CalculatorAcceleration implements Calculator<Double> {

	/** The value will change of only this fraction of difference to the new value */
	private final static double ACCELERATION_CHANGE_RATE = 0.6d;

	/** Maximum realistic acceleration to consider the acceleration as valid
     * Will ignore any accelaration greater than 2g's
     * 2g = 19.6 m/s^2 */
	public static final double MAX_ACCELERATION = 20; // m/s^2

	
	// The calculated acceleration (m/s^2)
	private double acceleration;

	/**
	 * Update the location. The new value for the acceleration
	 * will be calculated based on the updated location
	 * @see com.gvalentin.speedodyno.data.Calculator#update(android.location.Location, android.location.Location)
	 */
	@Override
	public void update(Location previous, Location current) {
		if (current != null && previous != null) {
			long dt = current.getTime()  - previous.getTime();
			// Check that elapsed time is not too high
			// (would mean that application has been paused for some time)
			if (dt > 0 && dt < 10000) {
				// Calculate acceleration (m/s^2)
				double dV = current.getSpeed() - previous.getSpeed();
				double newAcceleration = dV * 1000 / dt;
				
				// Filter max acceleration
				if (newAcceleration < MAX_ACCELERATION) {
					// If acceleration inversion, reinit to 0
					if ((newAcceleration < 0 && acceleration > 0) || (newAcceleration > 0 && acceleration < 0)) {
						acceleration = 0;
					} else {
						// Smoothen acceleration
						acceleration = acceleration + (newAcceleration - acceleration)*ACCELERATION_CHANGE_RATE;
					}
				}
			}
		}
	}

	/**
	 * Returns the calculated acceleration
	 * @see com.gvalentin.speedodyno.data.Calculator#getData()
	 */
	@Override
	public Double getData() {
		return acceleration;
	}
}
